/*
 * Copyright:  2018 smarabbit studio.
 *
 *  Licensed under the Confluent Community License; you may not use this file
 *  except in compliance with the License.  You may obtain a copy of the License at
 *
 *  http://www.confluent.io/confluent-community-license
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 *  WARRANTIES OF ANY KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations under the License.
 *
 *  @作   者： 黄开晖 (117227773@qq.com)
 *  @日   期:  2020年9月4日
 */
package com.massyframework.beanskin.runtime.service;

import java.util.Map;
import java.util.Objects;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.massyframework.beanskin.Module;
import com.massyframework.beanskin.plugin.Plugin;
import com.massyframework.beanskin.service.ServiceFactory;
import com.massyframework.beanskin.service.ServicePropertiesBuilder;
import com.massyframework.beanskin.service.ServiceReference;
import com.massyframework.beanskin.service.ServiceRegistration;
import com.massyframework.beanskin.service.ServiceRegistry;

/**
 * {@link ServiceRegistryDelegate} 代理{@link ServiceRegistry}的服务，将请求转发给{@link ServiceAdmin}处理。
 */
final class ServiceRegistryDelegate implements ServiceRegistry {

	private static Logger LOG = LoggerFactory.getLogger(ServiceRegistryDelegate.class);
    private final ServiceAdmin serviceAdmin;
    private final Module<?> module;

    /**
     * 构造方法
     * @param module {@link Module}, 注册服务的模块
     * @parm serviceAdmin {@link ServiceAdmin}, 服务管理器
     */
    public ServiceRegistryDelegate(Module<?> module, ServiceAdmin serviceAdmin){
        this.module =
                Objects.requireNonNull(module, "\"module\" cannot be null.");
        this.serviceAdmin =
                Objects.requireNonNull(serviceAdmin, "\"serviceAdmin\" cannot be null.");
    }

    /**
     * 使用<code>service</code>实例注册服务
     *
     * @param exportType  {@link Class}, 服务类型
     * @param service     {@link S}, 服务实例
     * @param svcProps    {@link Map}, 服务属性，可以为null.
     * @return {@link ServiceRegistration}
     */
    @Override
    public <S> ServiceRegistration<S> register(Class<S> exportType, S service, Map<String, Object> svcProps) {
        ServicePropertyExtendBuilder builder = ServicePropertyExtendBuilder.newBuilder(svcProps)
                .property(ServiceReference.SERVICE_ID, ServiceIdGenerator.genericServiceId())
                .property(ServiceReference.MODULE_GROUPID, module.getGroupId())
                .property(ServiceReference.MODULE_MODULEID, module.getModuleId())
                .property(ServiceReference.MODULE_VERSION, module.getVersion())
                .exportType(exportType);

        return this.doRegisterService(builder.getExportTypes(), service, builder, module, this.serviceAdmin);
    }

    /**
     * 使用<code>service</code>实例注册服务
     *
     * @param exportTypes {@link Class}数组, 服务类型
     * @param service      {@link Object}, 服务实例
     * @param svcProps     {@link Map}, 服务属性，可以为null.
     * @return {@link ServiceRegistration}
     */
    @Override
    public ServiceRegistration<?> register(Class<?>[] exportTypes, Object service, Map<String, Object> svcProps) {
        ServicePropertyExtendBuilder builder = ServicePropertyExtendBuilder.newBuilder(svcProps)
                .property(ServiceReference.SERVICE_ID, ServiceIdGenerator.genericServiceId())
                .property(ServiceReference.MODULE_GROUPID, module.getGroupId())
                .property(ServiceReference.MODULE_MODULEID, module.getModuleId())
                .property(ServiceReference.MODULE_VERSION, module.getVersion())
                .exportTypes(exportTypes);

        return this.doRegisterService(builder.getExportTypes(), service, builder, this.module, this.serviceAdmin);
    }

    /**
     * 使用<code>factory</code>实例注册服务
     *
     * @param exportType  {@link Class}, 服务类型
     * @param factory     {@link ServiceFactory}, 服务工厂
     * @param svcProps    {@link Map}, 服务属性，可以为null.
     * @return {@link ServiceRegistration}
     */
    @Override
    public <S> ServiceRegistration<S> register(Class<S> exportType, ServiceFactory<S> factory, Map<String, Object> svcProps) {
        ServicePropertyExtendBuilder builder = ServicePropertyExtendBuilder.newBuilder(svcProps)
                .property(ServiceReference.SERVICE_ID, ServiceIdGenerator.genericServiceId())
                .property(ServiceReference.MODULE_GROUPID, module.getGroupId())
                .property(ServiceReference.MODULE_MODULEID, module.getModuleId())
                .property(ServiceReference.MODULE_VERSION, module.getVersion())
                .exportType(exportType);

        return this.doRegisterServiceFactory(builder.getExportTypes(), factory, builder, this.module, this.serviceAdmin);
    }

    /**
     * 使用<code>factory</code>实例注册服务
     *
     * @param exportTypes {@link Class}数组, 服务类型
     * @param factory      {@link ServiceFactory}, 服务工厂
     * @param svcProps     {@link Map}, 服务属性，可以为null.
     * @return {@link ServiceRegistration}
     */
    @Override
    public ServiceRegistration<?> register(Class<?>[] exportTypes, ServiceFactory<?> factory, Map<String, Object> svcProps) {
        ServicePropertyExtendBuilder builder = ServicePropertyExtendBuilder.newBuilder(svcProps)
                .property(ServiceReference.SERVICE_ID, ServiceIdGenerator.genericServiceId())
                .property(ServiceReference.MODULE_GROUPID, module.getGroupId())
                .property(ServiceReference.MODULE_MODULEID, module.getModuleId())
                .property(ServiceReference.MODULE_VERSION, module.getVersion())
                .property(ServiceReference.MODULE_IDENTIFIER, module.toIdentifier())
                .exportTypes(exportTypes);
        return this.doRegisterServiceFactory(builder.getExportTypes(), factory, builder, this.module, this.serviceAdmin);
    }

    private <S> boolean doUnregister(RegistrationImpl<S> registration, boolean force){
    	if (!force) {
    		//当模块为插件，且处于销毁阶段，才能注销服务.
    		if (this.module instanceof Plugin) {
    			if (!this.serviceAdmin.isDestroying()) {
    				if (LOG.isWarnEnabled()) {
    					LOG.warn("The service registed by " + this.module + ", it unregister only with framework destorying, skip.");
    				}
    				return false;
    			}
    		}
    	}
    	
        return this.serviceAdmin.removeRegistration(registration, this.module);
    }

    /**
     * 注册服务
     * @param exportTypes {@link Class}数组，服务类型
     * @param service {@link S}, 服务实例
     * @param propBuilder {@link ServicePropertiesBuilder}, 服务属性构建器
     * @param module {@link Module}, 注册服务的模块
     * @param serviceAdmin {@link ServiceAdmin}, 服务管理器
     * @param <S>
     * @return {@link RegistrationImpl}
     */
    protected <S> RegistrationImpl<S> doRegisterService(Class<?>[] exportTypes,
                                                               S service, ServicePropertiesBuilder propBuilder,
                                                               Module<?> module, ServiceAdmin serviceAdmin){
        RegistrationImpl<S> result = new RegistrationImpl<S>(service, propBuilder);
        this.serviceAdmin.addRegistration(result, module);
        return result;
    }

    /**
     * 注册服务工厂
     * @param exportTypes  {@link Class}数组，服务类型
     * @param factory {@link ServiceFactory},服务工厂
     * @param propBuilder {@link ServicePropertiesBuilder}, 服务属性构建器
     * @param module {@link Module}, 注册服务的模块
     * @param serviceAdmin {@link ServiceAdmin}, 服务管理器
     * @param <S>
     * @return {@link RegistrationImpl}
     */
    protected <S> RegistrationImpl<S> doRegisterServiceFactory(Class<?>[] exportTypes,
                                                                      ServiceFactory<S> factory,
                                                                      ServicePropertiesBuilder propBuilder,
                                                                      Module<?> module, ServiceAdmin serviceAdmin){
        RegistrationImpl<S> result = new RegistrationImpl<S>(factory, propBuilder);
        this.serviceAdmin.addRegistration(result, module);
        return result;
    }

    private class RegistrationImpl<S> extends AbstractServiceRegistration<S> {

        /**
         * 构造方法
         * @param service {@link Object}, 服务实例
         * @param builder {@link ServicePropertiesBuilder}, 服务属性构建器
         */
        public RegistrationImpl(Object service, ServicePropertiesBuilder builder) {
            super(service, builder);
        }

        /**
         * 取消注册
         */
        @Override
        public boolean unregister(boolean force) {
            return doUnregister(this, force);
        }
    }
}
